package service.validation;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.validation.Errors;
import service.configuration.IFieldDateConfig;
import entities.Status;
import service.validation.FieldValidator;

public class DateValidator {
	
	/**
	 * Retrouve la date à partir de la chaine de caractère fournie en argument.
	 * 
	 * @param value la date sous forme de chaine de caractère
	 * @param format le format de la date souhaité
	 * @return
	 */
	private Date parseDate(String value, String format) {
		Date date;
		try {
			SimpleDateFormat df = new SimpleDateFormat(format);
			df.setLenient(false);
			
			try {
				date = df.parse(value);
			} catch (ParseException e ) {
				return null;
			}
			
		} catch (IllegalArgumentException e) {
			return null;
		} catch (NullPointerException e) {
			return null;
		}
		return date;
	}
	
	/**
	 * Teste si la valeur respecte la date minimun spécifiée dans la configuration.
	 * 
	 * @param value la valeur du champs à tester
	 * @param conf la confgiguration du champs de type date
	 * @return true si la limite est précisée et respectée, false sinon
	 */
	private boolean exceedLowerLimit(Date date, IFieldDateConfig conf) {
		return conf.getMin() != null &&  date.before(conf.getMin());
	}
	
	/**
	 * Teste si la valeur respecte la date maximum spécifiée dans la configuration.
	 * 
	 * @param value la valeur du champs à tester
	 * @param conf la confgiguration du champs de type date
	 * @return true si la limite est précisée et respectée, false sinon
	 */
	private boolean exceedUpperLimit(Date date, IFieldDateConfig conf) {
		return conf.getMax() != null && date.after(conf.getMax());
	}
	
	
	/**
	 * Teste la validité de la valeur d'un champs de type date.
	 * 
	 * @param value la valeur du champs à tester
	 * @param conf la confgiguration du champs de type date
	 * @return le status du champs SoftError ou Valid
	 */
	public Status validate(String value, IFieldDateConfig conf) {
		if (conf == null || value == null) {
			return FieldValidator.statusValid;
		}
		
		Date date = parseDate(value, conf.getFormat());
		
		if (date == null) {
			return FieldValidator.statusError;
		}
		
		if (exceedLowerLimit(date, conf) || exceedUpperLimit(date, conf)) {
			return FieldValidator.statusError;
		}
		
		return FieldValidator.statusValid;
	}
	
	/**
	 * Teste la validité de la valeur d'un champs de type date,
	 * et lie le champs à un message d'erreur en cas d'erreur.
	 * 
	 * @param name le nom du champs, util pour lier un message d'erreur au champs
	 * @param value la valeur du champs à tester
	 * @param conf la confgiguration du champs de type date
	 * @param errors mapping permettant de lier erreurs et messages
	 * @return le status du champs SoftError ou Valid
	 */
	public Status validate(String name, String value, IFieldDateConfig conf, Errors errors) {
		if (conf == null || value == null) {
			return FieldValidator.statusValid;
		}
		
		Date date = parseDate(value, conf.getFormat());
		
		if (date == null) {
			errors.rejectValue(name, "error.field.date.invalid", new Object[] {conf.getFormat()}, "");
			return FieldValidator.statusError;
		}
		
		// TODO : Ajouter la date min dans le message d'erreur
		if (exceedLowerLimit(date, conf)) {
			errors.rejectValue(name, "error.field.date.beforemin");
			return FieldValidator.statusError;
		}
		
		// TODO : Ajouter la date max dans le message d'erreur
		if (exceedUpperLimit(date, conf)) {
			errors.rejectValue(name, "error.field.date.aftermax");
			return FieldValidator.statusError;
		}
		
		return FieldValidator.statusValid;
	}
}
